#include"sock.hpp"
#define NUM 1024
#define DFL_FD -1
namespace so_sever
{
  class Select_Sever
  {
    private:
      int listen_sock;
      unsigned short port;
    public:
      Select_Sever(unsigned short _port):port(_port)
      {}
      //先初始化fd，起任务，填充select变量
      void InitSelectSever()
      {
       listen_sock= so_Sock::so_sock::Socket();
       so_Sock::so_sock::Bind(listen_sock,port);
       so_Sock::so_sock::Listen(listen_sock);
      }
      void Run()
      {
        fd_set rfds;
        int fd_array[NUM]={0};
        //让数组中所有数据都变成-1，然后填充对应的监听套接字
        clearArrar(fd_array,NUM,DFL_FD);
        fd_array[0]=listen_sock;
        for( ; ;)
        {
          //select时间也需要设置，输入输出型参数
          struct timeval timeout={5,0};

          //对所有的合法fd重新设置
          int maxfd=DFL_FD;
          FD_ZERO(&rfds);//对select中读描述符进行重新设置
          //对文件描述符数组进行判断
          for(int i=0;i<NUM;i++)
          {
            if(fd_array[i]==DFL_FD)
            {
              continue;
            }
           //合法的文件描述符 
           FD_SET(fd_array[i],&rfds);
           if(fd_array[i]>maxfd)
           {
             maxfd=fd_array[i];
           }
          }
           //select 阻塞等待
           
           switch (select(maxfd+1,&rfds,nullptr,nullptr,/*&timeout*/ nullptr))
           {
             case 0:
               std::cout<<"timeout....... "<<timeout.tv_sec<<std::endl;
              break;
             case -1:
               std::cout<<"select error "<<std::endl;
              break;
             default:
             // std::cout<<"select wait success"<<std::endl;
              Hander(rfds,fd_array,NUM);
              break;
           }//end switch 
          }//end for
        }
      void Hander(const fd_set &rfds,int fd_array[],int num)
      {
        //读取套接字
        //如何判断套接字已经等待成功 在fd数组里&&rfds里面这个已经存在
        for(int i=0;i<num;i++)
        {
          if(fd_array[i]==DFL_FD)
          {
            continue;
          }
          //说明这个文件描述符已存在
          if(FD_ISSET(fd_array[i],&rfds) && fd_array[i]==listen_sock)
          {
              //说明等待成功
              //接受套接字等待成功，读事件还没有就绪
              struct sockaddr_in peer;
              socklen_t len=sizeof(peer);
              //这里会不会阻塞,不会，已经有套接字加入到数组里面，
              int sock=accept(fd_array[i],(struct sockaddr*)&peer,&len);
              if(sock<0)
              {
                std::cout<<"accept error"<<std::endl;
                continue;
              }
              //端口转换
              uint16_t peer_port=htons(peer.sin_port);
              //ip转换
              std::string peer_ip=inet_ntoa(peer.sin_addr);

              std::cout<<"get a new link "<<" port "<<peer_port<<" ip "<<peer_ip<<std::endl;
              //走到这里 能否读取数据？？  不能 recv是IO，select只是等
              //要将文件描述符添加到fd——fd_arr
              //  
              if(!AddFdTorray(fd_array,num,sock))
              {
                //说明没添加成功
                close(sock);
                std::cout << "select server is full, close fd : " << sock << std::endl;
              }
          }//end if 
          else 
          {
            //说明可以读取数据了
            if(FD_ISSET(fd_array[i],&rfds))
            {
              //是一个合法的fd，并且可以读取了
          //是一个合法的fd，并且已经就绪了,是读数据事件就绪
          //实现读写,会阻塞吗？？绝对不会
            char buffer[1024];
          //你能确定你读完了请求吗？？？
          //如果我一条链接给你发了多个请求数据，但是每个都只有10字节, 粘包？
          //如果没有读到一个完整的报文，数据可能丢失
          //这里我们怎么保证自己能拿到完整的数据呢？？
          //1. 定制协议
              //2. 还要给每一个sock定义对应的缓冲区
              //ssize_t s=read(fd_array[i],buffer,sizeof(buffer)-1);
              ssize_t s=recv(fd_array[i],buffer,sizeof(buffer)-1, 0);
              if(s>0)
              {
                buffer[s]=0;
                std::cout<<buffer<<std::endl;
              }
              else if(s == 0)
              {
                std::cout<<"  client close "<<std::endl;
                //对端关闭
                close(fd_array[i]);
                fd_array[i]=DFL_FD;//清除文件描述符
              }
              else 
              {
                  std::cout<<" recv error "<<std::endl;
                  close(fd_array[i]);
                  fd_array[i]=DFL_FD;
              }
            }
            else 
            {
              //todo
            }
          }//end if

         }//end for
      }
      ~Select_Sever()
      {}
    private:
      void clearArrar(int fd_array[],int num,int default_fd)
      {
        for(int i=0;i<num;i++)
        {
          fd_array[i]=default_fd;
        }
      }
      bool AddFdTorray(int fd_array[],int num,int sock)
      {
        for(int i=0;i<num;i++)
        {
          if(fd_array[i]==DFL_FD)
          {
            fd_array[i]=sock;
            return true;
          }
        }
        return false;
      }



  };
}
